package istar.behaviour;

import istar.IElement;
import istar.IistarBehaviour;
import istar.agent.IstarJadeAgent;
import istar.impl.MeansEndLink;
import istar.impl.Task;
import istar.impl.TaskDecompositionLink;
import istar.onto.IstarOntology;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.AID;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.FSMBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.domain.DFService;
import jade.domain.FIPANames;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

public class RequestExternalBehaviour extends FSMBehaviour implements IistarBehaviour{

	static final String searching_providers_state = "SEARCHING_PROVIDERS"; 
	static final String negotiation_state = "NEGOTIATION"; 
	static final String request_state = "REQUEST";
	static final String wait_for_response_state = "WAIT_FOR_RESPONSE";
	static final String finalization_state ="FINALIZATION";
	static final String reset_state = "RESET_STATE";
	static final String error_state = "ERROR_STATE";
	
	//
	static final int searching_successful = 100;
	static final int searching_unsuccessful = -100;
	static final int negotiation_successful = 200;
	static final int negotiation_unsuccessful = -200;
	static final int request_successful = 300;
	static final int request_unsuccessful = -300;
	static final int wait_response_successful = 400;
	static final int wait_response_unsuccessful = -400;
	boolean finalization_sucessful = false;
	//static final int limit_for_waiting_proposal_response = 30000; 
	
	private Codec codec = new SLCodec();
	private Ontology ontology = IstarOntology.getInstance();
	private IElement dependum;
	private IElement dependerElement;
	private boolean log = true;
	private HashMap<String, Integer> qttSuccessMsgReceived = new HashMap<String, Integer>();
	private HashMap<String, Integer> qttFailureMsgReceived = new HashMap<String, Integer>();
	private HashMap<String, Integer> qttRequestMsgSent = new HashMap<String, Integer>();

	private List<Object> parameters = new Vector<Object>();
	
	private String conversationID;
	private ArrayList<Object> contentResponses = new ArrayList<Object>(); 
	
	private boolean error = false;
	private boolean done = false;
	private boolean completed = false;
	
	private long estimatedTotalTime;

	
	DFAgentDescription[] providers = null;
	private HashMap<String, ArrayList<AID>> committed = new HashMap<String, ArrayList<AID>>();
	private HashMap<String, ArrayList<AID>> rejected = new HashMap<String, ArrayList<AID>>();
	private HashMap<String, HashMap<AID, Long>> agreeded = new HashMap<String, HashMap<AID, Long>>();
	private HashMap<String, ArrayList<AID>> failured = new HashMap<String, ArrayList<AID>>();	
	private HashMap<String, ArrayList<AID>> succeeded = new HashMap<String, ArrayList<AID>>();	

	
	public RequestExternalBehaviour(IstarJadeAgent a, IElement _dependum) {
		super(a);
		this.dependum = _dependum;
		this.dependerElement = _dependum.getDependencies().get(0).getDependerElement();
		this.setup();
	}
	
	
	public RequestExternalBehaviour(IstarJadeAgent a, IElement _dependum, IElement _depender){
		super(a);
		this.dependum = _dependum; 
		this.dependerElement = _depender;
		this.setup();
	}

	
	
	@Override
	public long getEstimatedWaitingTime() {
		// TODO Auto-generated method stub
		return estimatedTotalTime;
	}

	@Override
	public String getExecutionNumber() {
		// TODO Auto-generated method stub
		return dependerElement.getExecutionNumber();
	}
	
	private String getTicket(){
		return ((IstarJadeAgent)myAgent).getTicket(); 
	}
	
	private void setup(){
		
		committed.clear(); 
		rejected.clear();
		agreeded.clear();
		failured.clear();


		Behaviour searching_providers = new AbstractIstarBehaviour((IstarJadeAgent)myAgent, dependerElement) {
			
			@Override
			public void myAction() throws Exception {
				log("Starting searching_providers behaviour");
				System.out.println(myAgent.getName()+ " Starting searching_providers behaviour");
				setEstimatedTime(10000);
				IElement endElement =  dependerElement.getSupports().get(0).getOwner();
				dependerElement.getContent().clear();
								
				//changed here
				//parameters.addAll(this.getParameters());
				Object depParameter = ((IstarJadeAgent)myAgent).getParameter(getExecutionNumber(), endElement.getName());
				if (((IstarJadeAgent)myAgent).getParameter(getExecutionNumber(), dependerElement.getName())!=null){
					depParameter = ((IstarJadeAgent)myAgent).getParameter(getExecutionNumber(), dependerElement.getName());
				}

				try {
					parameters.addAll((List<Object>)depParameter);
				} catch (Exception e) {
					parameters.add(depParameter);
				}
				
				if (parameters!=null && parameters.size()>0){	
					// 	Search for Dependees
				  	log(myAgent.getName()+" searching for services of type " + dependum.getTopic() +"/>");
			  		// Build the description used as template for the search
			  		DFAgentDescription template = new DFAgentDescription();
			  		ServiceDescription sd = new ServiceDescription();
			  		sd.setType(dependum.getTopic());
	  		  		sd.addOntologies(IstarOntology.getInstance().getName());
	  		  		sd.addLanguages(FIPANames.ContentLanguage.FIPA_SL);
			  		template.addServices(sd);
			  		providers = DFService.search(myAgent, template);
				}
			}

			@Override
			public int myOnEnd() {
				if (providers.length>0){
					return searching_successful;
				}
				else
					return -searching_unsuccessful;
			}

			@Override
			public boolean done() {
				return true;
			}
			
			
		};

		Behaviour negotiation = new AbstractIstarBehaviour((IstarJadeAgent)myAgent, dependerElement) {
			
			private static final int propose = 0;
			private static final int waiting_reply = 1;
			private static final int negotiation_end = 2;
			long start_waiting_time;
			int proposalResponses=0;
			
			int step=propose;
			
			@Override
			public void myAction() {
				log("Starting negotiation behaviour");
				System.out.println(myAgent.getName()+ " Starting negotiation behaviour");
				setEstimatedTime(30000);
				switch (step) {
				case propose:
					log("negotiation behaviour: executing propose step");
					System.out.println(myAgent.getName()+ " negotiation behaviour: executing propose step");
					for (int i = 0; i < providers.length; ++i) {
		  				DFAgentDescription dfd = providers[i];
		                AID provider = dfd.getName();
		                //ArrayList<AID> failuredAgents = failured.get(getTicket());
		                if (failured.get(getTicket())!=null){
		                	if (!failured.get(getTicket()).contains(provider)){
		                		break;
		                	}
		                }
		                if (committed.get(getTicket())!=null){
		                	if (!committed.get(getTicket()).contains(provider)){
		                		break;
		                	}
		                }
		                if (rejected.get(getTicket())!=null){
		                	if (!rejected.get(getTicket()).contains(provider)){
		                		break;
		                	}
		                }

		                log("Provider name="+ dfd.getName());
						ACLMessage proposalMsg = new ACLMessage(ACLMessage.PROPOSE);
						proposalMsg.setLanguage(codec.getName());
						proposalMsg.setOntology(ontology.getName());
						proposalMsg.addReceiver(provider);
		  				conversationID = dependerElement.getExecutionNumber();
						proposalMsg.setConversationId(conversationID);
						proposalMsg.addUserDefinedParameter("topic", dependum.getTopic());
	    				log("Sending a proposal message " + conversationID + " to agent " + provider.getName() );
	    				myAgent.send(proposalMsg);
		                
					}
					step = waiting_reply;
					start_waiting_time = Calendar.getInstance().getTimeInMillis();
					break;
					
				case waiting_reply:
					log("negotiation behaviour: executing waiting_reply step");
					System.out.println(myAgent.getName()+ " negotiation behaviour: executing waiting_reply step");
						// successful (READY) reply
						MessageTemplate mtReady = MessageTemplate.MatchConversationId(conversationID);
						mtReady.MatchPerformative(READY);
						ACLMessage readyMsg = myAgent.receive(mtReady);
						if (readyMsg!=null){
							if (readyMsg.getUserDefinedParameter("topic").equals(dependum.getTopic())){
								ArrayList<AID> commitedAgents = committed.remove(getTicket());
								if (commitedAgents==null){
									commitedAgents = new ArrayList<AID>();
								}
								commitedAgents.add(readyMsg.getSender());
								committed.put(getTicket(), commitedAgents);
								proposalResponses++;
			    				log("Received a 'READY' response for " + conversationID + " from agent " + readyMsg.getSender() );
			    				System.out.println(myAgent.getName()+ " Received a 'READY' response for " + conversationID + " from agent " + readyMsg.getSender() );
							}
						}

						MessageTemplate mtBusy= MessageTemplate.MatchConversationId(conversationID);
						mtBusy.MatchPerformative(BUSY);
						ACLMessage busyMsg = myAgent.receive(mtBusy);
						if (busyMsg!=null){
							if (busyMsg.getUserDefinedParameter("topic").equals(dependum.getTopic())){
								log("Received a 'BUSY' response " + conversationID + " from agent " + readyMsg.getSender() );
			    				System.out.println(myAgent.getName()+ " Received a 'BUSY' proposal response " + conversationID + " from agent " + readyMsg.getSender());
			    				//
			    				if ((committed.get(getTicket())==null) || (committed.get(getTicket()).isEmpty())){
			    					ACLMessage waitingMsg = busyMsg.createReply();
			    					waitingMsg.setPerformative(WAITING);
			    					waitingMsg.addUserDefinedParameter("topic", dependum.getTopic());
			    					myAgent.send(waitingMsg);
			    					HashMap<AID, Long> agreededAgents = agreeded.remove(getTicket());
									if (agreededAgents==null){
										agreededAgents = new HashMap<AID, Long>();
									}
									String content = busyMsg.getContent();
									Long estimatedTime = new Long(content.substring(content.indexOf("<EstimatedTime=" + 15), content.indexOf("/>")));
									agreededAgents.put(busyMsg.getSender(), estimatedTime);
									agreeded.put(getTicket(), agreededAgents);
			    				}
								proposalResponses++;
								
							}
						}
						
						MessageTemplate mtRejected = MessageTemplate.MatchConversationId(conversationID);
						mtRejected.MatchPerformative(ACLMessage.REJECT_PROPOSAL);
						ACLMessage rejectMsg = myAgent.receive(mtRejected);
						if (rejectMsg!=null ){
	    					if (rejectMsg.getUserDefinedParameter("topic").equals(dependum.getTopic())){
								ArrayList<AID> rejectedAgents = rejected.remove(getTicket());
								if (rejectedAgents==null){
									rejectedAgents = new ArrayList<AID>();
								}
								rejectedAgents.add(rejectMsg.getSender());
								rejected.put(getTicket(), rejectedAgents);

								proposalResponses++;
			    				log("Received an rejected proposal response " + conversationID + " from agent " + rejectMsg.getSender());
			    				System.out.println(myAgent.getName()+ " Received an rejected proposal response " + conversationID + " from agent " + rejectMsg.getSender());
	    						
	    					}
						}

					if (proposalResponses>=providers.length){
						step=negotiation_end;
						log("Negotiation received all responses");
						System.out.println(myAgent.getName()+ " Negotiation received all responses");
					}
					
					if (Calendar.getInstance().getTimeInMillis() > (start_waiting_time + getEstimatedWaitingTime())){
							log("Waiting times exceeded the limit of " + getEstimatedWaitingTime() + " milliseconds");
							System.out.println(myAgent.getName()+ " Waiting times exceeded the limit of " + getEstimatedWaitingTime() + " milliseconds");
							step=negotiation_end;
					}
					break;
				default:
					break;
				}
			}

			@Override
			public boolean done() {
				if (step==negotiation_end){
					return true;
				}
				else 
					return false;
			}

			@Override
			public int myOnEnd() {
				log("Ending negotiation Behaviour");
				if (committed.get(getTicket())!=null)
					if (!committed.get(getTicket()).isEmpty())
						return negotiation_successful;

				if (agreeded.get(getTicket())!=null)
					if (!agreeded.get(getTicket()).isEmpty())
						return negotiation_unsuccessful;
				
				return 0;
			}
			
			
		};
		
		Behaviour request = new AbstractIstarBehaviour((IstarJadeAgent)myAgent, dependerElement) {
			private static final int initial = 0;
			private static final int sending_commited = 1;
			private static final int waiting_agreeded_ready = 2;
			private static final int sending_agreeded = 3;
			private static final int request_finalization = 4;
			
			private HashMap<String, ArrayList<AID>> agreededReadyAgents= new HashMap<String, ArrayList<AID>>();
			
			long limitToWaitAgreeded;
			int step = initial;
			int index;
			long longerAgreededTime =0;

  			int qttObjectsToBeSent;
  			int qttObjectsSent;
			int qttCommitted = 0;
			int qttAgreeded = 0;
			int qttAgreededReady = 0;
			Double floor;
			int objsPerMsg;
			
			@Override
			public void myAction() throws Exception {
				log("Starting request behaviour");
				System.out.println(myAgent.getName()+ " Starting request behaviour");
				switch (step) {
				case initial:
					log("request behaviour: executing initial step");
					System.out.println(myAgent.getName()+ " request behaviour: executing initial step");
					if (agreeded.get(getTicket())!=null){
						Iterator<Long> itAgreededTime = agreeded.get(getTicket()).values().iterator();
						while (itAgreededTime.hasNext()){
							Long agreededTime = itAgreededTime.next();
							if (agreededTime>longerAgreededTime)
								longerAgreededTime = agreededTime;
						}
					}
					limitToWaitAgreeded = Calendar.getInstance().getTimeInMillis() + longerAgreededTime;
					
					qttObjectsToBeSent = parameters.size();
					if (committed.get(getTicket())!=null){
		  				qttCommitted = committed.get(getTicket()).size();
					}
					if (agreeded.get(getTicket())!=null){
		  				qttAgreeded = agreeded.get(getTicket()).size();
					}
						
	  				floor = Math.floor(qttObjectsToBeSent/(qttCommitted + qttAgreeded));
	  				if (floor!= (qttObjectsToBeSent/(qttCommitted + qttAgreeded)))
	  					floor++;
	  				objsPerMsg = floor.intValue();

	  				qttObjectsSent=0;
					step = sending_commited;
					break;

				case sending_commited:
					log("request behaviour: executing sending_commited step");
					System.out.println(myAgent.getName()+ " request behaviour: executing sending_commited step");

					log(myAgent.getName()+" found the following services providers:");
		  			for (int i = 0; i < committed.get(getTicket()).size(); ++i) {
		  				AID committedProvider = committed.get(getTicket()).get(i);
	                    log("Provider name="+ committedProvider.getName());
	    				ACLMessage msgRequest = new ACLMessage(ACLMessage.REQUEST);
	    				msgRequest.setLanguage(codec.getName());
	    				msgRequest.setOntology(ontology.getName());
	    				msgRequest.addReceiver(committedProvider);
	    				msgRequest.addUserDefinedParameter("topic", dependum.getTopic());
		  				conversationID = dependerElement.getExecutionNumber();
						msgRequest.setConversationId(conversationID);
						ArrayList<String> msgContents = new ArrayList<String>();
	    				if (i!=committed.get(getTicket()).size()-1){
	    					for (int j=0;j<objsPerMsg;j++){
	    						index = i*objsPerMsg + j;
				  				msgContents.add((String)parameters.get(index));
				  				qttObjectsSent++;
	    					}
		  				}
		  				else {
	    					for (int j=0;j<objsPerMsg;j++){
	    						index = i*objsPerMsg + j;
	    						if (index<qttObjectsToBeSent){
	    							msgContents.add((String)parameters.get(index));
	    							qttObjectsSent++;
	    						}
	    					}
		  				}
	    				
	    				msgRequest.setContentObject(msgContents);
	    				myAgent.send(msgRequest);
	    				if (qttRequestMsgSent.containsKey(conversationID)){
	        				int msgSent = qttRequestMsgSent.remove(conversationID);
				  			msgSent++;
				  			qttRequestMsgSent.put(conversationID, msgSent);
	    				}
	    				else {
	    					qttRequestMsgSent.put(conversationID, new Integer(1));
	    				}
	    				
	    				log("Sending message " + conversationID + " to agent " + committedProvider.getName() );
	    				
					  	for (int k=0;k<msgContents.size();k++){
	        				log("Message content: " + msgContents.get(k));
					  	}

		  			}
		  			
		  			if (agreeded.get(getTicket())!=null){
			  			step = waiting_agreeded_ready;
			  			
		  			}
		  			else{
		  				parameters.clear();
		  				step = request_finalization;
		  			}
					break;
					
				case waiting_agreeded_ready:
					log("request behaviour: executing waiting_agreeded_ready step");
					System.out.println(myAgent.getName()+ " request behaviour: executing waiting_agreeded_ready step");
					if ((agreededReadyAgents.get(getTicket()).size() < agreeded.get(getTicket()).size()) &&
						(Calendar.getInstance().getTimeInMillis() < limitToWaitAgreeded)){
						MessageTemplate mtAgreededReady = MessageTemplate.MatchConversationId(conversationID);
						mtAgreededReady .MatchPerformative(IistarBehaviour.READY);
						ACLMessage agreededReadyMsg = myAgent.receive(mtAgreededReady);
						if (agreededReadyMsg !=null ){
							if (agreededReadyMsg.getUserDefinedParameter("topic").equals(dependum.getTopic())){
								ArrayList<AID> agreededReady = agreededReadyAgents.remove(getTicket());
								if (agreededReady==null){
									agreededReady = new ArrayList<AID>();
								}
								agreededReady.add(agreededReadyMsg.getSender());
								agreededReadyAgents.put(getTicket(), agreededReady);

								log("Received a 'READY' message referering to " + conversationID + " from the agreeded agent " + agreededReadyMsg.getSender());
								System.out.println(myAgent.getName()+ " Received a 'READY' message referering to " + conversationID + " from the agreeded agent " + agreededReadyMsg.getSender());
								
							}
						}
					}
					else {
						step = sending_agreeded;
					}
					break;

				case sending_agreeded:
					log("request behaviour: executing sending_agreeded step");
					System.out.println(myAgent.getName()+ " request behaviour: executing sending_agreeded step");
		  			qttObjectsToBeSent = parameters.size() - qttObjectsSent;
	  				qttAgreededReady = agreededReadyAgents.get(getTicket()).size();
	  				floor = Math.floor(qttObjectsToBeSent/(qttAgreededReady));
	  				if (floor!= (qttObjectsToBeSent/(qttAgreededReady)))
	  					floor++;
	  				objsPerMsg = floor.intValue();

					
		  			for (int i = 0; i < agreededReadyAgents.get(getTicket()).size(); ++i) {
		  				AID agreededReady = agreededReadyAgents.get(getTicket()).get(i);
	                    log("Provider name="+ agreededReady.getName());
	    				ACLMessage msgRequest = new ACLMessage(ACLMessage.REQUEST);
	    				msgRequest.setLanguage(codec.getName());
	    				msgRequest.setOntology(ontology.getName());
	    				msgRequest.addReceiver(agreededReady);
	    				msgRequest.addUserDefinedParameter("topic", dependum.getTopic());
		  				conversationID = dependerElement.getExecutionNumber();
						msgRequest.setConversationId(conversationID);
						ArrayList<String> msgContents = new ArrayList<String>();
	    				if (i!=agreededReadyAgents.get(getTicket()).size()-1){
	    					for (int j=0;j<objsPerMsg;j++){
	    						int index = i*objsPerMsg + j;
				  				msgContents.add((String)parameters.get(index));
				  				qttObjectsSent++;
	    					}
		  				}
		  				else {
	    					for (int j=0;j<objsPerMsg;j++){
	    						int index = i*objsPerMsg + j;
	    						if (index<qttObjectsToBeSent){
	    							msgContents.add((String)parameters.get(index));
	    							qttObjectsSent++;
	    						}
	    					}
		  				}
	    				
	    				msgRequest.setContentObject(msgContents);
	    				myAgent.send(msgRequest);
	    				if (qttRequestMsgSent.containsKey(getTicket())){
	        				int msgSent = qttRequestMsgSent.remove(getTicket());
				  			msgSent++;
				  			qttRequestMsgSent.put(getTicket(), msgSent);
	    				}
	    				else {
	    					qttRequestMsgSent.put(getTicket(), new Integer(1));
	    				}
	    				
	    				log("Sending a 'REQUEST' message " + getTicket() + " to agent " + agreededReady.getName() );
	    				
					  	for (int k=0;k<msgContents.size();k++){
	        				log("Message content: " + msgContents.get(k));
					  	}
		  			}
		  			step = request_finalization;
		  			parameters.clear();
					break;
					
				case request_finalization:
					log("request behaviour: executing finalization step - will start 'wait_for_response behaviour' ");
					System.out.println(myAgent.getName()+ " request behaviour: executing finalization step - will start 'wait_for_response behaviour' ");
					parameters.clear();
					break;
					
				default:
					break;
				}
				
  				
			}

			@Override
			public int myOnEnd() {
				if (qttObjectsToBeSent==qttObjectsSent){
					log("request behaviour ending successfully ");
					System.out.println(myAgent.getName()+ " request behaviour ending successfully ");
					return request_successful;
				}
				else{
					return request_unsuccessful;
				}
			}

			@Override
			public boolean done() {
				return true;
			}
			
		};
		

		
		Behaviour wait_for_response = new AbstractIstarBehaviour((IstarJadeAgent)myAgent, dependerElement) {
			@Override
			public void myAction() {
				MessageTemplate mtSuccessReply = MessageTemplate.MatchConversationId(conversationID);
				mtSuccessReply.MatchPerformative(ACLMessage.INFORM);
				ACLMessage successReply = myAgent.receive(mtSuccessReply);
				if (successReply!=null ){
					if (successReply.getUserDefinedParameter("topic").equals(dependum.getTopic())){
						System.out.println(myAgent.getName() + " Received a response in 'wait_for_response' behaviour");

						ArrayList<AID> succeededAgents = succeeded.remove(getTicket());
						if (succeededAgents==null){
							succeededAgents = new ArrayList<AID>();
						}
						succeededAgents.add(successReply.getSender());
						succeeded.put(getTicket(), succeededAgents);

						if (committed.get(getTicket())!=null)
							committed.get(getTicket()).remove(successReply.getSender());
						
						if (agreeded.get(getTicket())!=null)
							agreeded.get(getTicket()).remove(successReply.getSender());

						if (qttSuccessMsgReceived.containsKey(getTicket())){
							Integer qttRec = qttSuccessMsgReceived.remove(getTicket());
							qttRec++;
							qttSuccessMsgReceived.put(getTicket(), qttRec);
						}
						else {
							qttSuccessMsgReceived.put(getTicket(), new Integer(1));
						}

						try {
							contentResponses.add(successReply.getContentObject());
							log("Received a REPLY about " + getTicket() + " from " + successReply.getSender().getName() + " with content:" + successReply.getContentObject().toString());
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}

				MessageTemplate mtFailureReply = MessageTemplate.MatchConversationId(conversationID);
				mtFailureReply.MatchPerformative(ACLMessage.FAILURE);
				ACLMessage failureReply = myAgent.receive(mtFailureReply);

				if (failureReply!=null ){
					if (failureReply.getUserDefinedParameter("topic").equals(dependum.getTopic())){
						ArrayList<AID> failuredAgents = failured.remove(getTicket());
						if (failuredAgents==null){
							failuredAgents = new ArrayList<AID>();
						}
						failuredAgents.add(failureReply.getSender());
						failured.put(getTicket(), failuredAgents);

						if (committed.get(getTicket())!=null)
							committed.get(getTicket()).remove(successReply.getSender());
						if (agreeded.get(getTicket())!=null)
							agreeded.get(getTicket()).remove(successReply.getSender());

						if (qttFailureMsgReceived.containsKey(getTicket())){
							Integer qttRec = qttFailureMsgReceived.remove(getTicket());
							qttRec++;
							qttFailureMsgReceived.put(getTicket(), qttRec);
						}
						else {
							qttFailureMsgReceived.put(getTicket(), new Integer(1));
						}

						log("Received a FAILURE REPLY about " + getTicket() + " from " + failureReply.getSender().getName() );
						
					}

				}

				if (qttRequestMsgSent.get(getTicket()).equals(qttSuccessMsgReceived.get(getTicket()))){
					done = true;
					completed = true;
				}
				else {
					int msgsSucess = 0;
					int msgsFail = 0;
					if (qttSuccessMsgReceived.get(getTicket())!=null)
						msgsSucess = qttSuccessMsgReceived.get(getTicket());
					if (qttFailureMsgReceived.get(getTicket())!=null)
						msgsFail = qttFailureMsgReceived.get(getTicket());
					
					if ((msgsSucess+msgsFail)==qttRequestMsgSent.get(getTicket())){
						done = true;
					}
				}
				
			}

			@Override
			public boolean done() {
				return done;
			}

			@Override
			public int myOnEnd() {
				if (completed){
					return wait_response_successful;
				}
				else { 
					if (done)
						return wait_response_unsuccessful;
					else
						return 0;
				}
			}

			
		};		

		Behaviour finalization = new AbstractIstarBehaviour((IstarJadeAgent)myAgent, dependerElement) {
			@Override
			public void myAction() {
				log("Starting finalization behaviour");
				System.out.println(myAgent.getName() + " Starting finalization behaviour");

				//changed here
				//setResult(contentResponses);
				((IstarJadeAgent)myAgent).setResult(getExecutionNumber(), dependerElement.getName(), contentResponses);

				
			}

			@Override
			public boolean done() {
				return true;
			}

			@Override
			public int myOnEnd() {
				((IstarJadeAgent)myAgent).log("Ending finalization behaviour");
				System.out.println(myAgent.getName() + " Ending finalization behaviour");
				finalization_sucessful = true;
				return 1;
			}
		};		

		Behaviour error = new Behaviour((IstarJadeAgent)myAgent) {
			@Override
			public void action() {
				((IstarJadeAgent)myAgent).log("Starting error behaviour");
				System.out.println(myAgent.getName() + " Starting error behaviour");

				// TODO Auto-generated method stub
				ACLMessage workingMsg = ((IstarJadeAgent)myAgent).getWorkingMessages().get(dependum.getExecutionNumber()); 
				ACLMessage reply = workingMsg.createReply();
				reply.addUserDefinedParameter("topic", dependum.getTopic());
				reply.setPerformative(ACLMessage.FAILURE);
				((IstarJadeAgent)myAgent).send(reply);
			}

			@Override
			public boolean done() {
				return true;
			}
		};	
		


		this.registerTransition(searching_providers_state, searching_providers_state, 0);
		this.registerTransition(searching_providers_state, negotiation_state, searching_successful);

		this.registerTransition(negotiation_state, request_state, negotiation_successful);
		this.registerTransition(negotiation_state, searching_providers_state, 0);
		
		this.registerTransition(request_state, request_state, request_unsuccessful);
		this.registerTransition(request_state, wait_for_response_state, request_successful);
		
		this.registerTransition(wait_for_response_state, request_state, wait_response_unsuccessful);
		this.registerTransition(wait_for_response_state, wait_for_response_state, 0);
		this.registerTransition(wait_for_response_state, finalization_state, wait_response_successful);
		
		this.registerDefaultTransition(error_state, reset_state);
		this.registerDefaultTransition(reset_state, searching_providers_state);

		this.registerTransition(searching_providers_state, error_state, AbstractIstarBehaviour.ERROR_STATE_CODE);
		this.registerTransition(negotiation_state, error_state, AbstractIstarBehaviour.ERROR_STATE_CODE);
		this.registerTransition(request_state, error_state, AbstractIstarBehaviour.ERROR_STATE_CODE);
		this.registerTransition(wait_for_response_state, error_state, AbstractIstarBehaviour.ERROR_STATE_CODE);
		this.registerTransition(finalization_state, error_state, AbstractIstarBehaviour.ERROR_STATE_CODE);
		
		this.registerFirstState(searching_providers, searching_providers_state);
		this.registerState(negotiation, negotiation_state);
		this.registerState(request, request_state);
		this.registerState(wait_for_response, wait_for_response_state);
		this.registerLastState(finalization, finalization_state);

		this.registerState(new ResetBehaviour(this), reset_state);

		estimatedTotalTime = ((AbstractIstarBehaviour)searching_providers).getEstimatedWaitingTime() +
							 ((AbstractIstarBehaviour)negotiation).getEstimatedWaitingTime() +
							 ((AbstractIstarBehaviour)request).getEstimatedWaitingTime() +
							 ((AbstractIstarBehaviour)wait_for_response).getEstimatedWaitingTime() +
							 ((AbstractIstarBehaviour)finalization).getEstimatedWaitingTime();
	}
	
	
	
	@Override
	public int onEnd() {
		if (finalization_sucessful){
			System.out.println(myAgent.getName() +  " running onEnd() returning 0 ");
			return 0;
		}
		else {
			System.out.println(myAgent.getName() +  " running onEnd() returning -1 ");
			return -1;
		}
	}



	private class ResetBehaviour extends OneShotBehaviour {
		private FSMBehaviour mainFSM;

		public ResetBehaviour(FSMBehaviour _fsm){
			super();
			this.mainFSM= _fsm;
		}
		public void action() {
			mainFSM.reset();
		}

		@Override
		public int onEnd() {
			return 1;
		}
	}

}





